package com.blt.govdata.log;
/*
 * Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合.
 * args()
 * @args()
 * execution()
 * this()
 * target()
 * @target()
 * within()
 * @within()
 * @annotation
 * 其中execution 是用的最多的,其格式为:
 * execution 表达式,其格式为:
 * execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
 * returning type pattern,name pattern, and parameters pattern是必须的.
 * ret-type-pattern:可以为*表示任何返回值,全路径的类名等.
 * name-pattern:指定方法名,*代表所以,set*,代表以set开头的所有方法.
 * parameters pattern:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型.
 * 举例说明:
 * 任意公共方法的执行：
 * execution(public * *(..))
 * 任何一个以“set”开始的方法的执行：
 * execution(* set*(..))
 * AccountService 接口的任意方法的执行：
 * execution(* com.xyz.service.AccountService.*(..))
 * 定义在service包里的任意方法的执行：
 * execution(* com.xyz.service.*.*(..))
 * 定义在service包和所有子包里的任意类的任意方法的执行：
 * execution(* com.xyz.service..*.*(..))
 * 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行：
 * execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
 * 最靠近(..)的为方法名,靠近.*(..))的为类名或者接口名,如上例的JoinPointObjP2.*(..))
 * pointcutexp包里的任意类.
 * within(com.test.spring.aop.pointcutexp.*)
 * pointcutexp包和所有子包里的任意类.
 * within(com.test.spring.aop.pointcutexp..*)
 * 实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类.
 * this(com.test.spring.aop.pointcutexp.Intf)
 *
 * 当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型.
 *
 * 带有@Transactional标注的所有类的任意方法.
 * @within(org.springframework.transaction.annotation.Transactional)
 * @target(org.springframework.transaction.annotation.Transactional)
 * 带有@Transactional标注的任意方法.
 * @annotation(org.springframework.transaction.annotation.Transactional)
 * @within和@target针对类的注解,@annotation是针对方法的注解
 *
 * 参数带有@Transactional标注的方法.
 * @args(org.springframework.transaction.annotation.Transactional)
 * 参数为String类型(运行是决定)的方法.
 * args(String)
 * Pointcut 可以通过Java注解和XML两种方式配置
 */
/**
 * Created with IntelliJ IDEA
 * Description:自定义日志AOP
 * Author:GongJun
 * Date:2018/3/30
 * Time:16:33
 * blt Technologies Co., Ltd.
 */
import java.lang.reflect.Method;

import com.blt.govdata.core.annotation.Loggable;
import com.blt.govdata.model.TLog;
import com.blt.govdata.service.ITLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * @func 操作日志
 * @author GongJun
 * @date 2018/3/30
 */
// @Aspect的意思是面向切面编程，一个类前面加上@Aspect说明这个类使用了这个技术
@Aspect
// 这里就是说把这个类交给Spring管理，重新起个名字叫operationLogger，由于不好说这个类属于哪个层面，就用@Component
@Component(value = "operationLogger")
public class OperationLogger{
    @Autowired
    private ITLogService service;


    // @Pointcut是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的
    @Pointcut("execution(* *(..)) && @annotation(com.blt.govdata.core.annotation.Loggable)")
    public void log() {
    }

    // @AfterReturning(value="切入点表达式或命名切入点",pointcut="切入点表达式或命名切入点",argNames="参数列表参数名",returning="返回值对应参数名")
    @AfterReturning(value = "log()", returning = "retVal")
    public void log(JoinPoint point, Object retVal) {
        Object[] params = point.getArgs();// 获取参数
        String methodName = point.getSignature().getName();// 获取方法名
        Class<?> targetClass = point.getTarget().getClass();// 获取目标对象的类名
        Method method = null;
        for (Method mt : targetClass.getMethods()) {
            if (methodName.equals(mt.getName())) {
                method = mt;
                break;
            }
        }
        Loggable loggable = method.getAnnotation(Loggable.class);// 自定义注解
        if (loggable == null) {
            return;
        }
        String desc = loggable.describe();// 描述
        String optType = loggable.optType();// 方法名
        String module = loggable.module();// 日志模块
        if ("SELECT".equals(optType)) {// 选择
            selectLog(params, desc, module);
        } else if ("UPDATE".equals(optType)) {// 更新
            updateLog(params, desc, module);
        } else if ("INSERT".equals(optType)) {// 插入
            insert(params, desc, module);
        } else if ("DELETE".equals(optType)) {// 删除
            delete(params, desc, module);
        }
    }

    /**
     * @func 删除操作的日志
     * @date 2018/3/30
     * @param params
     * @param desc
     * @param module
     */
    private void delete(Object[] params, String desc, String module) {

    }

    /**
     * @func 插入操作的日志
     * @date 2018/3/30
     * @param params
     * @param desc
     * @param module
     */
    private void insert(Object[] params, String desc, String module) {

    }

    /**
     * @func 更新操作的日志
     * @date 2018/3/30
     * @param params
     * @param desc
     * @param module
     */
    private void updateLog(Object[] params, String desc, String module){
        if("room_log".equals(module)){  //房间日志表
            TLog tLog=new TLog();
            this.service.insert(tLog);
        }
    }

    /**
     * @func 查询操作的日志
     * @date 2018/3/30
     * @param params
     * @param desc
     * @param module
     */
    private void selectLog(Object[] params, String desc, String module) {

    }

}
